#ifndef __AI_SERVICE_MEMORY_POOL_H__
#define __AI_SERVICE_MEMORY_POOL_H__

#include <memory>

namespace ai_service {

class Block {
public:
    using sptr = std::shared_ptr<Block>;

    static sptr Create(const size_t bytes) {
        sptr ptr = std::shared_ptr<Block>(new Block());
        if (!ptr) {
            LOG_ERROR("make Block failed");
            return nullptr;
        }
        bool ret = ptr->Malloc(bytes);
        if (!ret) {
            return nullptr;
        }
        return ptr;
    }
    void Destroy() {
        free(m_buff);
        m_buff = NULL;
    }
    ~Block() {
        m_valid = true;
    }
    bool IsValid() const {
        return m_valid;
    }
    void Update() {
        m_valid = ~m_valid;
    }

    void* Data() {return m_buff;}
private:
    Block() {}

    bool Malloc(const size_t bytes) {
        m_buff = malloc(bytes);
        return m_buff != NULL;
    }
    void* m_buff = NULL;
    bool m_valid = false;
}; // struct Block


template <std::size_t ELN>
struct ElnMemoryPool
{
    using sptr = std::shared_ptr<ElnMemoryPool<ELN>>;

public:
    Block::sptr GetBlock(const int idx)
    {
        return m_blocks[idx];
    }
    static sptr Create(size_t bytes) {
        sptr ptr = std::make_shared<sptr>();
        if (!ptr) {
            LOG_ERROR("make ElnMemoryPool failed");
            return nullptr;
        }
        bool ret = true;
        for (int i = 0; i < ELN; ++i) {
            auto& block = ptr->GetBlock(i);
            block = Block::Create(bytes);
            if (!block[i]) {
                return nullptr;
            }
        }
        return ptr;
    }

    ~ElnMemoryPool() {
        for (int i = 0; i < ELN; ++i) {
            m_blocks[i]->Destroy();
        }
    }

    Block::sptr Alloc() {
        for (int i = 0; i < ELN; ++i) {
            if (m_blocks[i]->IsValid()) {
                m_blocks[i]->Update();
                return m_blocks[i];
            }
        }
        LOG_WARN("no valid memory");
        return NULL;
    }

private:
    ElnMemoryPool() {}

    size_t m_bytes;
    std::array<Block::sptr, ELN> m_blocks;
}; // struct MemoryPool


}

#endif // __AI_SERVICE_MEMORY_POOL_H__